package com.comba.patch.tool.service;

import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.List;

import org.apache.commons.io.FileUtils;

import com.comba.patch.tool.conf.Configuration;
import com.comba.patch.tool.utils.AntPathMatcher;
import com.comba.patch.tool.utils.PatchUtils;
import com.google.common.base.Function;
import com.google.common.collect.Collections2;

public class PatchOverviewService {

	@SuppressWarnings("unchecked")
	public void making(File originalDir, File currentDir, File patchDir, ProgressListener progressListener) throws IOException {

		new Thread(new Runnable() {

			@Override
			public void run() {
				Collection<File> currentFiles = FileUtils.listFiles(currentDir, null, true);

				Collection<String> excludeFileFullPatterns = getExcludeFileFullPatterns(currentDir,
						Configuration.getInstance().getExcludeFilePatterns());

				int currentFileTotalCount = currentFiles.size();
				int processedProcessCount = 0;
				for(File currentFile : currentFiles) {
					processedProcessCount++;
					if(progressListener != null) {
						progressListener.onProgress(currentFileTotalCount, processedProcessCount);
					}
					if(!isExcluded(currentFile.getAbsolutePath(), excludeFileFullPatterns)) {
						try {
							String relativePath = PatchUtils.getRelativePath(currentDir, currentFile);
							File originalFile = new File(originalDir, relativePath);
							if(PatchOverviewService.this.isNew(originalFile, currentFile)) {
								FileUtils.copyFile(currentFile, new File(patchDir, relativePath));
							} else if(PatchOverviewService.this.isModified(originalFile, currentFile)) {
								FileUtils.copyFile(currentFile, new File(patchDir, relativePath));
							}
						} catch (Exception e) {
							if(progressListener != null) {
								progressListener.onException(currentFileTotalCount, processedProcessCount, e);
							}
							return;
						}
					}
				}
				if(progressListener != null) {
					progressListener.onComplete();
				}
			}
		}).start();


	}


	private boolean isNew(File originalFile, File currentFile) {
		return !originalFile.exists();
	}

	private boolean isModified(File originalFile, File currentFile) throws IOException {
		if(originalFile.exists()) {
			String originalMd5 = PatchUtils.md5(originalFile);
			String currentMd5 = PatchUtils.md5(currentFile);
			return !originalMd5.equals(currentMd5);
		} else {
			return false;
		}

	}

	private boolean isExcluded(String path, Collection<String> excludeFilePatterns) {
		path = path.replaceAll("\\\\", "/");
		AntPathMatcher matcher = new AntPathMatcher();
		for(String excludeFilePattern : excludeFilePatterns) {
			if(matcher.match(excludeFilePattern, path)) {
				return true;
			}
		}
		return false;
	}


	private Collection<String> getExcludeFileFullPatterns(final File dir, List<String> excludeFilePatterns) {
		return Collections2.transform(excludeFilePatterns, new Function<String, String>() {

			@Override
			public String apply(String input) {
				input = input.replaceAll("\\\\", "/");
				String dirPath = dir.getAbsolutePath().replaceAll("\\\\", "/");
				return input.startsWith("/") ? (dirPath + input) : (dirPath + "/" + input);
			}
		});
	}

}
